package mongo

import (
	"context"
	"github.com/qiniu/qmgo/operator"
	"github.com/qiniu/qmgo/options"
	"time"
)

type callback = func(ctx context.Context, doc interface{}, opType operator.OpType, opts ...interface{}) error

// MonMongoPlugin mon打点插件。其中的doc或者opt中必须传指针类型的
func MonMongoPlugin(ctx context.Context, doc interface{}, opType operator.OpType, opts ...interface{}) error {
	// do anything
	if hook, ok := doc.(*MonMongoHook); ok {
		hook.executeHook(opType)
		return nil
	}

	if len(opts) > 0 {
		if hook, ok := opts[0].(*MonMongoHook); ok {
			hook.executeHook(opType)
		}
	}

	return nil
}

// NewQueryMonOpt 使用时将其放置到Find的opt中
// 示例： cli := WrapperMongo.Client.Database("test_db").Collection("test_collection")
//		 cli.Find(ctx, bson.M{"_id": objId}, mongo.NewQueryMonOpt("test_db", "test_collection")).One(&res)
func NewQueryMonOpt(database, collection string) options.FindOptions {
	return options.FindOptions{
		QueryHook: &MonMongoHook{
			DB:            database,
			Collection:    collection,
			OperationName: "query",
		},
	}
}

// NewInsertMonOpt 使用时将其放置到Insert的opt中
// 示例：cli.InsertOne(ctx, UserInfo{}, mongo.NewInsertMonOpt("test_db", "test_collection"))
func NewInsertMonOpt(database, collection string) options.InsertOneOptions {
	return options.InsertOneOptions{
		InsertHook: &MonMongoHook{
			DB:            database,
			Collection:    collection,
			OperationName: "insert",
		},
	}
}

func NewInsertManyMonOpt(database, collection string) options.InsertManyOptions {
	return options.InsertManyOptions{
		InsertHook: &MonMongoHook{
			DB:            database,
			Collection:    collection,
			OperationName: "insert_many",
		},
	}
}

func NewUpsertMonOpt(database, collection string) options.UpsertOptions {
	return options.UpsertOptions{
		UpsertHook: &MonMongoHook{
			DB:            database,
			Collection:    collection,
			OperationName: "upsert",
		},
	}
}

func NewUpdateMonOpt(database, collection string) options.UpdateOptions {
	return options.UpdateOptions{
		UpdateHook: &MonMongoHook{
			DB:            database,
			Collection:    collection,
			OperationName: "update",
		},
	}
}

func NewReplaceMonOpt(database, collection string) options.ReplaceOptions {
	return options.ReplaceOptions{
		UpdateHook: &MonMongoHook{
			DB:            database,
			Collection:    collection,
			OperationName: "replace",
		},
	}
}

func NewRemoveMonOpt(database, collection string) options.RemoveOptions {
	return options.RemoveOptions{
		RemoveHook: &MonMongoHook{
			DB:            database,
			Collection:    collection,
			OperationName: "remove",
		},
	}
}

func (p *MonMongoHook) executeHook(opType operator.OpType) {
	switch opType {
	case operator.BeforeInsert, operator.BeforeUpsert, operator.BeforeReplace, operator.BeforeUpdate, operator.BeforeQuery, operator.BeforeRemove:
		_ = p.Before()
	case operator.AfterInsert, operator.AfterUpsert, operator.AfterReplace, operator.AfterUpdate, operator.AfterQuery, operator.AfterRemove:
		_ = p.After()
	}
}

type MonMongoHook struct {
	DB            string
	Collection    string
	OperationName string
	StartTime     time.Time
}

func (p *MonMongoHook) Before() error {
	p.StartTime = time.Now()
	return nil
}

func (p *MonMongoHook) After() error {
	// mod打点，没有该功能
	return nil
}
